package org.example.cloud.controller;

import cn.hutool.core.date.DateUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.example.cloud.api.PayFeignApi;
import org.example.cloud.entities.dto.PayDTO;
import org.example.cloud.util.ResultData;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @author 宋孟林
 * @description restTemplate 是微服务双方用于互相通信的template ，使用 url 访问的方式
 * @date: 2025/4/5 12:30
 */
@RestController
@Slf4j
@RequestMapping("/order")
public class OrderController {
    /**
     * 如果使用硬编码的方式会存在非常多的问题
     * 1.如果订单微服务和支付微服务改变了ip地址和端口，则支付微服务将变得不可用，需要同步修改订单微服务中调用支付微服务的端口号
     * 2.如果系统中提供了很多订单微服务和支付微服务。则无法实现微服务的负载均衡功能。
     * 3.如果系统需要支持更高的并发，需要部署更多的订单微服务和支付微服务，硬编码订单微服务则后续的维护会变得异常复杂
     * 所以在微服务开发中，需要引入服务治理的功能，实现微服务之间的动态注册和发现，从此刻开始正式进入SpringCloud
     */
//    private static final String PAY_SERVICE_URL = "http://localhost:8081";
    //将硬编码的端口和ip改为微服务名称
//    private static final String PAY_SERVICE_URL = "http://cloud-payment-service-provider";
//    @Resource
//    private RestTemplate restTemplate;

    @Resource
    private DiscoveryClient discoveryClient;
    @Resource
    private PayFeignApi payFeignApi;

    /**
     * 由报错信息可知，当前默认请求超时时间默认是等待60s。如果超过60秒就直接在服务消费者端报错
     * 但是服务提供者那边是还在执行，可能数据已经插入或者更新了，但是给服务消费者反映的是更新失败了(分布式事务如何控制？)
     * @param payDto 参数
     * @return 返回响应结果
     */
    @Transactional
    @GetMapping("/add")
    public ResultData<?> addOrder(@RequestBody PayDTO payDto){
        log.info("订单控制器业务执行");
        ResultData<?> resultData = null;
        log.info("订单控制器方法执行,调用支付方法开始执行，当前时间为： {}", DateUtil.now());
        resultData = payFeignApi.addPay(payDto);
        log.info("结束时间为： {}", DateUtil.now());
        return resultData;
    }

    @DeleteMapping("/delete/{id}")
    public ResultData<?> deleteOrder(@PathVariable("id") Integer id){
        log.info("订单删除逻辑执行");
        return payFeignApi.deletePay(id);
    }

    /**
     * restTemplate使用exchange()方法来发送除了post和get之外的请求，如果发送的是json数据类型，先创建请求头对象将媒体类型设置为json
     * 将请求参数(json)和请求头作为为参数后创建请求体对象，请求体对象作为exchange方法的请求参数，会创建一个响应体，我们返回响应体的body就可以了
     * @param payDTO 请求参数
     * @return 响应体对象
     */
    @PutMapping("/update")
    public ResultData<?> updateOrder(@RequestBody PayDTO payDTO) {
        log.info("订单更新逻辑执行");
        log.info("✅消费者开始执行 PUT 请求：{}", payDTO);
        return payFeignApi.updatePay(payDTO);
    }

    @GetMapping("/get/{id}")
    public ResultData<?> getOrderById(@PathVariable("id") Integer id){
        log.info("获取订单逻辑开始执行");
        return payFeignApi.getById(id);
    }

    @GetMapping("/getAll")
    public ResultData<?> getAllOrder(){
        log.info("获取所有订单");
        return payFeignApi.selectAll();
    }

    /**
     * 使用自动注入的 discoveryClient 获取当前已经存在的服务
     * @return 服务名集合
     */
    @GetMapping("/consumer/discover")
    public ResultData<List<?>> discoverAllService(){
        List<String> services = discoveryClient.getServices();
        for (String element : services) {
            log.info("当前的服务有： {}", element);
        }
        log.info("=======================");
        List<ServiceInstance> clientInstances = discoveryClient.getInstances("cloud-payment-service-provider");
        for (ServiceInstance instance : clientInstances) {
            log.info("当前支付微服务提供者有： {}", instance);
        }
        return ResultData.success(services);
    }

}
